use hypers::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Extract)]
#[cookie]
pub struct CookieParams {
    hypers: Option<String>,
    rust: Option<String>,
}

#[derive(Serialize, Deserialize, Extract)]
#[header]
pub struct HeaderParams {
    pub host: Option<String>,
    pub accept: Option<String>,
    #[serde(rename = "User-Agent")]
    pub user_agent: Option<String>,
}

#[derive(Serialize, Deserialize, Extract)]
#[param]
pub struct UrlParams {
    pub age: Option<u16>,
    #[serde(rename = "firstName")]
    pub first_name: Option<String>,
    #[serde(rename = "lastName")]
    pub last_name: Option<String>,
}

#[derive(Serialize, Deserialize, Extract)]
#[query]
pub struct QueryParams {
    pub email: Option<String>,
    pub age: Option<u16>,
}

#[derive(Serialize, Deserialize, Extract)]
#[body]
pub struct BodyParams {
    pub email: Option<String>,
    pub age: Option<u16>,
    #[serde(rename = "firstName")]
    pub first_name: Option<String>,
}

#[derive(Serialize, Deserialize, Extract)]
#[body]
pub struct Input {
    #[header]
    pub host: Option<String>,

    #[header]
    //#[serde(rename(deserialize = "user-agent"))]
    #[serde(rename = "user-agent")]
    pub user_agent: Option<String>,

    #[header]
    pub accept: Option<String>,

    #[cookie]
    pub hypers: Option<String>,

    #[cookie]
    pub rust: Option<String>,

    #[param]
    pub id: Option<u16>,

    #[query]
    pub name: Option<String>,

    #[query]
    pub age: Option<u16>,

    #[serde(rename = "firstName")]
    pub first_name: Option<String>,

    #[extract(rename = "Last-Name", alias("lastName", "LastName"))]
    pub last_name: Option<String>,
}
struct Api;
#[controller(name = "extract")]
impl Api {
    // http://127.0.0.1:7878/extract/set_cookies
    #[get("/set_cookies")]
    pub async fn set_cookies() -> impl Responder {
        let mut cookie1 = Cookie::new("hypers", "hypers2023");
        cookie1.set_path("/extract");

        let mut cookie2 = Cookie::new("rust", "rust2023");
        cookie2.set_path("/extract");

        let mut cookie_jar = CookieJar::new();
        cookie_jar.add(cookie1);
        cookie_jar.add(cookie2);
        (200, cookie_jar)
    }

    // http://127.0.0.1:7878/extract/parse_cookies
    #[get("/parse_cookies")]
    pub async fn parse_cookies(cookie_param: CookieParams) -> impl Responder {
        (200, Json(cookie_param))
    }

    // http://127.0.0.1:7878/extract/header
    // Request Header Params
    #[get("/header")]
    pub async fn header(input: HeaderParams) -> impl Responder {
        (200, Json(input))
    }

    // http://127.0.0.1:7878/extract/admin@outlook.com/18
    // Uri Path Params
    #[delete("/:email/:age/:firstName")] // 参数是 email age
    pub async fn delete(data: UrlParams) -> impl Responder {
        (200, Json(data))
    }

    // http://127.0.0.1:7878/extract/query?email=admin@outlook.com&age=19
    // Query Params
    #[get("/query")] // 参数是 email age
    pub async fn query(data: QueryParams) -> impl Responder {
        (200, Json(data))
    }

    // http://127.0.0.1:7878/extract/create
    // Context-Type : application/json
    #[post("/create")] // 参数是 email age
    pub async fn create(data: BodyParams) -> Response {
        let mut res = Response::default();
        res.status(200).json(&data);
        res
    }

    // 这个接口应该在接口测试工具上测试
    // http://127.0.0.1:7878/extract/extract_input/11?name=admin&age=18
    #[post("extract_input/:id")]
    pub async fn extract_input(params: Input) -> impl Responder {
        (200, Json(params))
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    let mut root = Router::default();
    root.push(Api);
    println!("root = {:#?}", root);
    let listener = hypers::TcpListener::bind("127.0.0.1:7878").await?;
    hypers::listen(root, listener).await
}
